// ##############################
// ####  note:  bokeweilai framework other agora main fun
// ####  create:  TANWENHUI (twh:谭文辉)
// ####  date:   2024/6/18
// ##############################

#include "bkwl_common.h"
#include "dev_log.h"
#include "bkwl_agora_main.h"

// static uint8_t audio_type = 0;
// static uint32_t audio_samp_rate = 8000;
// static bool aec_enable = false;

// static beken_thread_t agora_thread_hdl = NULL;
static bool agora_runing = false;
static agora_rtc_config_t agora_rtc_config = DEFAULT_AGORA_RTC_CONFIG();
static agora_rtc_option_t agora_rtc_option = DEFAULT_AGORA_RTC_OPTION();

static uint32_t g_target_bps = BANDWIDTH_ESTIMATE_MIN_BITRATE;

// static aud_intf_drv_setup_t aud_intf_drv_setup = DEFAULT_AUD_INTF_DRV_SETUP_CONFIG();
static aud_intf_voc_setup_t aud_intf_voc_setup = DEFAULT_AUD_INTF_VOC_SETUP_CONFIG();
static aud_intf_work_mode_t aud_work_mode = AUD_INTF_WORK_MODE_NULL;

static bool g_connected_flag = false;
static char agora_appid[50] = {0};
static bool audio_en = false;
static bool video_en = false;

#if 0
static media_camera_device_t camera_device = {
	.num_uvc_dev = 2,
	.dualstream = 1,
	.d_mode = H264_MODE,
	.d_fmt = PIXEL_FMT_H264,
	.d_info.resolution.width = 1920,
	.d_info.resolution.height = 1080,
	.d_info.fps = FPS20,
#if 1 // defined(CONFIG_USB_UVC)
	.type = UVC_CAMERA,
	.mode = JPEG_MODE,
	.fmt = PIXEL_FMT_JPEG,
	/* expect the width and length */
	.info.resolution.width = 640,
	.info.resolution.height = 480,
	.info.fps = FPS20,
#elif defined(CONFIG_DVP_CAMERA)
	.type = DVP_CAMERA,
	.mode = H264_MODE,
	.fmt = PIXEL_FMT_H264,
	/* expect the width and length */
	.info.resolution.width = 1280,
	.info.resolution.height = 720,
	.info.fps = FPS20,
#endif
};
#else
static media_camera_device_t camera_device = {
    .num_uvc_dev = 1,
    .dualstream = 0,
    .d_mode = H264_MODE,
    .d_fmt = PIXEL_FMT_H264,
    .d_info.resolution.width = 640,
    .d_info.resolution.height = 480,
    .d_info.fps = FPS20,
#if 1 // defined(CONFIG_USB_UVC)
    .type = UVC_CAMERA,
    .mode = JPEG_MODE,
    .fmt = PIXEL_FMT_JPEG,
    /* expect the width and length */
    .info.resolution.width = 640,
    .info.resolution.height = 480,
    .info.fps = FPS20,
#elif defined(CONFIG_DVP_CAMERA)
    .type = DVP_CAMERA,
    .mode = H264_MODE,
    .fmt = PIXEL_FMT_H264,
    /* expect the width and length */
    .info.resolution.width = 1280,
    .info.resolution.height = 720,
    .info.fps = FPS20,
#endif
};
#endif

#if CONFIG_WIFI_ENABLE
extern void rwnxl_set_video_transfer_flag(uint32_t video_transfer_flag);
#else
#define rwnxl_set_video_transfer_flag(...)
#endif

static int lcd_id = 0;

int _display_turn_on(uint16_t id, uint16_t rotate, uint16_t fmt)
{
    LOGI("%s, id: %d, rotate: %d fmt: %d\n", __func__, id, rotate, fmt);

    const lcd_device_t *device = (const lcd_device_t *)media_app_get_lcd_device_by_id(id);
    if ((uint32_t)device == BK_FAIL || device == NULL)
    {
        LOGI("%s, could not find device id: %d\n", __func__, id);
        return BK_FAIL;
    }

    lcd_open_t lcd_open = {0};
    lcd_open.device_ppi = device->ppi;
    lcd_open.device_name = device->name;

#if 1 // (!CONFIG_SOC_BK7256XX)
    uint8_t rot_angle = 0;
    uint8_t pipeline_enable = true;
    if (pipeline_enable)
    {
        if (fmt == 0)
        {
            media_app_lcd_fmt(PIXEL_FMT_RGB565_LE);
        }
        else if (fmt == 1)
        {
            media_app_lcd_fmt(PIXEL_FMT_RGB888);
        }

        switch (rotate)
        {
        case 90:
            rot_angle = ROTATE_90;
            break;
        case 180:
            rot_angle = ROTATE_180;
            break;
        case 270:
            rot_angle = ROTATE_270;
            break;
        case 0:
        default:
            rot_angle = ROTATE_NONE;
            break;
        }
        media_app_pipline_set_rotate(rot_angle);
        media_app_lcd_pipeline_open(&lcd_open);
    }
    else
#endif
    {
        if (rotate == 90)
            media_app_lcd_rotate(ROTATE_90);

        media_app_lcd_open(&lcd_open);
    }

    lcd_id = id;
    return 0;
}

int _display_turn_off(void)
{
    LOGI("%s id %d", __func__, lcd_id);

#if 1 //(!CONFIG_SOC_BK7256XX)
    uint8_t pipeline_enable = true;
    if (pipeline_enable)
    {
        media_app_lcd_pipeline_close();
    }
    else
#endif
    {
        media_app_lcd_close();
    }

    lcd_id = 0;
    return 0;
}

static void agora_rtc_user_notify_msg_handle(agora_rtc_msg_t *p_msg)
{
    switch (p_msg->code)
    {
    case AGORA_RTC_MSG_JOIN_CHANNEL_SUCCESS:
        g_connected_flag = true;
        LOGI("Join channel success.\n");
        break;
    case AGORA_RTC_MSG_USER_JOINED:
        LOGI("User Joined.\n");
        break;
    case AGORA_RTC_MSG_USER_OFFLINE:
        LOGI("User Offline.\n");
        break;
    case AGORA_RTC_MSG_CONNECTION_LOST:
        LOGE("Lost connection. Please check wifi status.\n");
        g_connected_flag = false;
        break;
    case AGORA_RTC_MSG_INVALID_APP_ID:
        LOGE("Invalid App ID. Please double check.\n");
        break;
    case AGORA_RTC_MSG_INVALID_CHANNEL_NAME:
        LOGE("Invalid channel name. Please double check.\n");
        break;
    case AGORA_RTC_MSG_INVALID_TOKEN:
    case AGORA_RTC_MSG_TOKEN_EXPIRED:
        LOGE("Invalid token. Please double check.\n");
        break;
    case AGORA_RTC_MSG_BWE_TARGET_BITRATE_UPDATE:
        g_target_bps = p_msg->data.bwe.target_bitrate;
        break;
    default:
        break;
    }
}

#if 1 // defined(CONFIG_USB_UVC)
static void media_checkout_uvc_device_info(bk_uvc_device_brief_info_t *info, uvc_state_t state)
{
    bk_uvc_config_t uvc_config_info_param = {0};
    uint8_t format_index = 0;
    uint8_t frame_num = 0;
    uint8_t index = 0;

    if (state == UVC_CONNECTED)
    {
        uvc_config_info_param.vendor_id = info->vendor_id;
        uvc_config_info_param.product_id = info->product_id;

        format_index = info->format_index.mjpeg_format_index;
        frame_num = info->all_frame.mjpeg_frame_num;
        if (format_index > 0)
        {
            LOGI("%s uvc_get_param MJPEG format_index:%d\r\n", __func__, format_index);
            for (index = 0; index < frame_num; index++)
            {
                LOGI("uvc_get_param MJPEG width:%d heigth:%d index:%d\r\n",
                     info->all_frame.mjpeg_frame[index].width,
                     info->all_frame.mjpeg_frame[index].height,
                     info->all_frame.mjpeg_frame[index].index);
                for (int i = 0; i < info->all_frame.mjpeg_frame[index].fps_num; i++)
                {
                    LOGI("uvc_get_param MJPEG fps:%d\r\n", info->all_frame.mjpeg_frame[index].fps[i]);
                }

                if (info->all_frame.mjpeg_frame[index].width == camera_device.info.resolution.width && info->all_frame.mjpeg_frame[index].height == camera_device.info.resolution.height)
                {
                    uvc_config_info_param.frame_index = info->all_frame.mjpeg_frame[index].index;
                    uvc_config_info_param.fps = info->all_frame.mjpeg_frame[index].fps[0];
                    uvc_config_info_param.width = camera_device.info.resolution.width;
                    uvc_config_info_param.height = camera_device.info.resolution.height;
                }
            }
        }

        uvc_config_info_param.format_index = format_index;

        if (media_app_set_uvc_device_param(&uvc_config_info_param) != BK_OK)
        {
            LOGE("%s, failed\r\n, __func__");
        }
    }
    else
    {
        LOGI("%s, %d\r\n", __func__, state);
    }
}
#endif

void app_media_read_frame_callback(frame_buffer_t *frame)
{
    // printf("app_media_read_frame_callback(%u): data_len %d", rtos_get_time(), frame->length);
#if 1
    video_frame_info_t info = {0};

    info.stream_type = VIDEO_STREAM_HIGH;
    if (frame->fmt == PIXEL_FMT_JPEG)
    {
        info.data_type = VIDEO_DATA_TYPE_GENERIC_JPEG;
        info.frame_type = VIDEO_FRAME_KEY;
    }
    else if (frame->fmt == PIXEL_FMT_H264)
    {
        info.data_type = VIDEO_DATA_TYPE_H264;
        info.frame_type = VIDEO_FRAME_AUTO_DETECT;
    }
    else
    {
        LOGE("not support format: %d \r\n", frame->fmt);
    }

    bk_agora_rtc_video_data_send((uint8_t *)frame->frame, (size_t)frame->length, &info);
#endif

#if 0 // def CONFIG_USB_UVC
	int video_send_internal = 70;
	/* avoid send too fast by uvc. modify it by yourself */
	rtos_delay_milliseconds(video_send_internal);
#endif
}

static int agora_rtc_user_audio_rx_data_handle(unsigned char *data, unsigned int size, const audio_frame_info_t *info_ptr)
{
    bk_err_t ret = BK_OK;

    if ((info_ptr->data_type == AUDIO_DATA_TYPE_PCMA && aud_intf_voc_setup.data_type == AUD_INTF_VOC_DATA_TYPE_G711A) || (info_ptr->data_type == AUDIO_DATA_TYPE_PCMU && aud_intf_voc_setup.data_type == AUD_INTF_VOC_DATA_TYPE_G711U) || (info_ptr->data_type == AUDIO_DATA_TYPE_PCM && aud_intf_voc_setup.data_type == AUD_INTF_VOC_DATA_TYPE_PCM))
    {
        /* write a fram speaker data to speaker_ring_buff */
        ret = bk_aud_intf_write_spk_data((uint8_t *)data, (uint32_t)size);
        if (ret != BK_OK)
        {
            LOGE("write spk data fail \r\n");
        }
    }
    else
    {
        LOGE("audio data type:%d is not match voice data type: %d, size: %d.\n", info_ptr->data_type, aud_intf_voc_setup.data_type, size);
        ret = BK_FAIL;
    }

    return ret;
}

bk_err_t bkwl_agora_init()
{
    bk_err_t ret = BK_OK;
    tprintf("twh agora_main entry\n\n");
    bkwl_log_memory_free_show();

    tprintf("twh agora_main 1\n\n");
    // 2. API: init agora rtc sdk

    // service_opt.license_value[0] = '\0';
    agora_rtc_config.p_appid = (char *)psram_malloc(strlen(agora_appid) + 1);
    os_strcpy((char *)agora_rtc_config.p_appid, agora_appid);
    agora_rtc_config.log_disable = false;
    agora_rtc_config.bwe_param_max_bps = BANDWIDTH_ESTIMATE_MAX_BITRATE;
    tprintf("twh agora_main 2\n\n");
    ret = bk_agora_rtc_create(&agora_rtc_config, (agora_rtc_msg_notify_cb)agora_rtc_user_notify_msg_handle);
    tprintf("twh agora_main 3\n\n");
    if (ret != BK_OK)
    {
        tprintf("twh agora_main 4\n\n");
        tprintf("bk_agora_rtc_create fail \r\n");
    }
    // tprintf("-----start agora rtc process-----\r\n");

    tprintf("twh agora_main 5\n\n");
    tprintf("twh agora_main 6\n\n");
    agora_rtc_option.p_channel_name = (char *)psram_malloc(os_strlen(CONFIG_CHANNEL_NAME) + 1);
    os_strcpy((char *)agora_rtc_option.p_channel_name, CONFIG_CHANNEL_NAME);
    agora_rtc_option.audio_config.audio_data_type = CONFIG_AUDIO_CODEC_TYPE;
#if defined(CONFIG_SEND_PCM_DATA)
    agora_rtc_option.audio_config.pcm_sample_rate = CONFIG_PCM_SAMPLE_RATE;
    agora_rtc_option.audio_config.pcm_channel_num = CONFIG_PCM_CHANNEL_NUM;
#endif
    tprintf("twh agora_main 7\n\n");
    ret = bk_agora_rtc_start(&agora_rtc_option);
    tprintf("twh agora_main 8\n\n");
    if (ret != BK_OK)
    {
        tprintf("twh agora_main 9\n\n");
        tprintf("bk_agora_rtc_start fail, ret:%d \r\n", ret);
        return ret;
    }

    tprintf("twh agora_main 10\n\n");
    // tprintf("-----agora_rtc_join_channel start-----\r\n");
    // 5. wait until we join channel successfully
    while (!g_connected_flag)
    {
        // bkwl_log_memory_free_show();
        tprintf("twh agora_main 11\n\n");
        rtos_dump_task_runtime_stats();
        rtos_delay_milliseconds(5000);
    }

    tprintf("twh agora_main 12\n\n");
    tprintf("-----agora_rtc_join_channel success-----\r\n");

    return ret;
}

bk_err_t bkwl_agora_config()
{
    bk_err_t ret = BK_OK;

    agora_runing = true;

    if (audio_en)
    {
        tprintf("audio start \r\n");

        tprintf("twh agora_main 13\n\n");
        ret = bk_aud_intf_voc_start();
        tprintf("twh agora_main 14\n\n");
        if (ret != BK_ERR_AUD_INTF_OK)
        {
            tprintf("twh agora_main 15\n\n");
            tprintf("bk_aud_intf_voc_start fail, ret:%d \r\n", ret);
        }
        else
        {
            tprintf("twh agora_main 16\n\n");
            tprintf("bk_aud_intf_voc_start complete \r\n");
        }

        bkwl_log_memory_free_show();
    }

    tprintf("twh agora_main 17\n\n");
    if (video_en)
    {

        tprintf("twh agora_main 18\n\n");
        tprintf("\r\n--------video start num_uvc_dev %d, dualstream %d, type %d, mode %d, fmt %d info (%d * %d) \r\n",
                camera_device.num_uvc_dev, camera_device.dualstream, camera_device.type,
                camera_device.mode, camera_device.fmt, camera_device.info.resolution.height, camera_device.info.resolution.width);

        tprintf("\r\n--------video start d_mode %d, d_fmt %d, d_info (%d * %d) \r\n",
                camera_device.d_mode, camera_device.d_fmt, camera_device.d_info.resolution.height, camera_device.d_info.resolution.width);

        tprintf("twh agora_main 19\n\n");
        bk_wifi_set_wifi_media_mode(true);
        tprintf("twh agora_main 20\n\n");
        bk_wifi_set_video_quality(WIFI_VIDEO_QUALITY_FD);
        tprintf("twh agora_main 21\n\n");

        rwnxl_set_video_transfer_flag(true);

        tprintf("twh agora_main 27\n\n");
#if 1 // defined(CONFIG_USB_UVC)
        media_app_uvc_register_info_notify_cb(media_checkout_uvc_device_info);
#endif

        tprintf("twh agora_main 28\n\n");
        // bk_aggora_rtc_register_video_rx_handle((agora_rtc_video_rx_data_handle)bk_agora_rtc_video_data_send);

#if 1
        tprintf("twh agora_main 29\n\n");
        ret = media_app_camera_open(&camera_device);
        tprintf("twh agora_main 30\n\n");
        if (ret != BK_OK)
        {
            tprintf("twh agora_main 31\n\n");
            tprintf("%s media_app_camera_open failed\n", __func__);
            return ret;
        }

        tprintf("twh agora_main 32\n\n");
        bool media_mode = false;
        uint8_t quality = 0;
        bk_wifi_get_wifi_media_mode_config(&media_mode);
        tprintf("twh agora_main 33\n\n");
        bk_wifi_get_video_quality_config(&quality);
        tprintf("twh agora_main 34\n\n");
        tprintf("~~~~~~~~~~wifi media mode %d, video quality %d~~~~~~\r\n", media_mode, quality);

#if 1 // defined(CONFIG_USB_UVC)
#if 0 //(!CONFIG_SOC_BK7256XX)
		uint8_t rot_angle = ROTATE_NONE; // ROTATE_NONE ROTATE_180 ROTATE_270 ROTATE_90
		media_app_pipline_set_rotate(rot_angle);
#endif

        tprintf("twh agora_main 35\n\n");
#if defined(CONFIG_SEND_H264_FRAMES)
        tprintf("twh agora_main 36\n\n");
        ret = media_app_h264_pipeline_open();
        tprintf("twh agora_main 37\n\n");
        if (ret != BK_OK)
        {
            tprintf("twh agora_main 38\n\n");
            tprintf("%s h264_pipeline_open failed\n", __func__);
            return ret;
        }

        tprintf("twh agora_main 39\n\n");
        ret = media_app_register_read_frame_callback(PIXEL_FMT_H264, app_media_read_frame_callback);
        tprintf("twh agora_main 40\n\n");
        if (ret != BK_OK)
        {
            tprintf("twh agora_main 41\n\n");
            tprintf("%s register read_frame_cb failed\n", __func__);
            return ret;
        }
#else
        tprintf("twh agora_main 42\n\n");
        ret = media_app_register_read_frame_callback(camera_device.d_fmt, app_media_read_frame_callback);
        tprintf("twh agora_main 43\n\n");
        if (ret != BK_OK)
        {
            tprintf("twh agora_main 44\n\n");
            tprintf("%s register read_frame_cb failed\n", __func__);
            return ret;
        }
#endif
        tprintf("twh agora_main 45\n\n");
#elif defined(CONFIG_DVP_CAMERA)
        ret = media_app_register_read_frame_callback(camera_device.fmt, app_media_read_frame_callback);
        if (ret != BK_OK)
        {
            tprintf("%s register read_frame_cb failed\n", __func__);
            return ret;
        }
#endif
        bkwl_log_memory_free_show();

        //_display_turn_on(LCD_DEVICE_ST7701S, 0, 1);
        _display_turn_on(LCD_DEVICE_H050IWV, 0, 1);
#endif
    }

    return ret;
}

bk_err_t bkwl_agora_release()
{
    bk_err_t ret = BK_OK;

    tprintf("twh agora_main 48\n\n");
    /* free audio  */
    if (audio_en)
    {
        tprintf("twh agora_main 49\n\n");
        bk_aggora_rtc_register_audio_rx_handle(NULL);

        tprintf("twh agora_main 50\n\n");
        /* stop voice */
        ret = bk_aud_intf_voc_stop();
        tprintf("twh agora_main 51\n\n");
        if (ret != BK_ERR_AUD_INTF_OK)
        {
            tprintf("twh agora_main 52\n\n");
            tprintf("bk_aud_intf_voc_stop fail, ret:%d \r\n", ret);
        }
        else
        {
            tprintf("twh agora_main 53\n\n");
            tprintf("bk_aud_intf_voc_stop complete \r\n");
        }

        tprintf("twh agora_main 54\n\n");
        /* deinit vioce */
        ret = bk_aud_intf_voc_deinit();
        tprintf("twh agora_main 55\n\n");
        if (ret != BK_ERR_AUD_INTF_OK)
        {
            tprintf("twh agora_main 56\n\n");
            tprintf("bk_aud_intf_voc_deinit fail, ret:%d \r\n", ret);
        }
        else
        {
            tprintf("bk_aud_intf_voc_deinit complete \r\n");
        }

        tprintf("twh agora_main 57\n\n");
        /* deinit audio */
        aud_work_mode = AUD_INTF_WORK_MODE_NULL;
        bk_aud_intf_set_mode(aud_work_mode);

        tprintf("twh agora_main 58\n\n");
        ret = bk_aud_intf_drv_deinit();
        tprintf("twh agora_main 59\n\n");
        if (ret != BK_ERR_AUD_INTF_OK)
        {
            tprintf("twh agora_main 60\n\n");
            tprintf("bk_aud_intf_drv_deinit fail, ret:%d \r\n", ret);
        }
        else
        {
            tprintf("bk_aud_intf_drv_deinit complete \r\n");
        }
        tprintf("twh agora_main 61\n\n");
    }

    tprintf("twh agora_main 62\n\n");
    /* free audio  */
    if (video_en)
    {
        tprintf("twh agora_main 63\n\n");
        ret = media_app_unregister_read_frame_callback();
        tprintf("twh agora_main 64\n\n");
        if (ret != BK_OK)
        {
            tprintf("twh agora_main 65\n\n");
            tprintf("%s unregister read_frame_cb failed\n", __func__);
            return ret;
        }

#if 1 // defined(CONFIG_USB_UVC)
        tprintf("twh agora_main 66\n\n");
        ret = media_app_h264_pipeline_close();
        tprintf("twh agora_main 67\n\n");
        if (ret != BK_OK)
        {
            tprintf("twh agora_main 68\n\n");
            tprintf("%s h264_pipeline_close failed\n", __func__);
            return ret;
        }
#endif

        tprintf("twh agora_main 69\n\n");
        ret = media_app_camera_close(camera_device.type);
        tprintf("twh agora_main 70\n\n");
        if (ret != BK_OK)
        {
            tprintf("twh agora_main 71\n\n");
            tprintf("%s media_app_camera_close failed\n", __func__);
            return ret;
        }

        tprintf("twh agora_main 72\n\n");
        rwnxl_set_video_transfer_flag(false);

        tprintf("twh agora_main 73\n\n");
        bk_wifi_set_wifi_media_mode(false);
        tprintf("twh agora_main 74\n\n");
        bk_wifi_set_video_quality(WIFI_VIDEO_QUALITY_HD);
        tprintf("twh agora_main 75\n\n");
    }

    tprintf("twh agora_main 76\n\n");
    /* free agora */
    /* stop agora rtc */
    bk_agora_rtc_stop();
    tprintf("twh agora_main 77\n\n");

    /* destory agora rtc */
    bk_agora_rtc_destroy();
    tprintf("twh agora_main 78\n\n");

    if (agora_rtc_config.p_appid)
    {
        tprintf("twh agora_main 79\n\n");
        psram_free((char *)agora_rtc_config.p_appid);
        agora_rtc_config.p_appid = NULL;
    }

    tprintf("twh agora_main 80\n\n");
    if (agora_rtc_option.p_channel_name)
    {
        tprintf("twh agora_main 81\n\n");
        psram_free((char *)agora_rtc_option.p_channel_name);
        agora_rtc_option.p_channel_name = NULL;
    }

    tprintf("twh agora_main 82\n\n");
    audio_en = false;
    video_en = false;

    g_connected_flag = false;

    return ret;
}
